// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Client;
using System.IO;
using System.Diagnostics;
using Microsoft.TeamFoundation.Migration.Toolkit;
using System.Threading;
using Microsoft.TeamFoundation.Migration.Toolkit.VC;

namespace Microsoft.TeamFoundation.Migration.VersionControl.Wss
{
    public class Session : VersionControlSession
    {
        CultureInfo m_culture;

        /// <summary>
        /// Get the cultureinfo setting for the session. The default value is 1033(EN-US)
        /// </summary>
        public CultureInfo Culture
        {
            get
            {
                if (m_culture == null)
                {
                    m_culture = new CultureInfo(GetValue<int>("LanguageId", 1033));
                }
                return m_culture;
            }
        }

        private void AnalysisThread()
        {
            Thread.CurrentThread.Name = WSS2TFSResources.AnalysisThreadName;
            try
            {
                if (m_wssToTfsManager != null)
                {
                    WssToTfsAnalysisEngine w2t = new WssToTfsAnalysisEngine(this, m_wssToTfsManager);

                    w2t.Run();
                }
                sourceToTfsAnalysisComplete = true;

                if (m_tfsToWssManager != null)
                {
                    Tfs2WssAnalysisEngine t2w = new Tfs2WssAnalysisEngine(this, m_tfsToWssManager);
                    t2w.Run();
                }
                tfsToSourceAnalysisComplete = true;
            }
            catch (Exception ex)
            {
                TraceManager.TraceException(ex);
                Abort();
            }
        }

        private void MigrationThread()
        {
            Thread.CurrentThread.Name = WSS2TFSResources.MigrationThreadName;
            try
            {
                if (m_wssToTfsManager != null)
                {
                    WssToTfsMigrationEngine w2t = new WssToTfsMigrationEngine(this, m_wssToTfsManager);

                    // WSS uploads all actions are once so no need to migrate until analysis 
                    // is all done
                    while (!sourceToTfsAnalysisComplete)
                    {
                        ThrowIfAborted();
                        Thread.Sleep(1000);
                    }

                    // now we should get everything in one pass.
                    w2t.Run();
                }
                
                if (m_tfsToWssManager != null)
                {
                    Tfs2WssMigrationEngine t2w = new Tfs2WssMigrationEngine(this, m_tfsToWssManager);

                    // keep migrating while analysis is running.
                    while (!tfsToSourceAnalysisComplete)
                    {
                        ThrowIfAborted();
                        Thread.Sleep(1000);
                        t2w.Run();
                    }

                    // and then once more to make sure we got it all
                    t2w.Run();
                }
                Complete();
            }
            catch (Exception ex)
            {
                TraceManager.TraceException(ex);
                Abort();
            }
        }

        ChangeGroupingMananger m_wssToTfsManager;
        ChangeGroupingMananger m_tfsToWssManager;

        Thread m_analysisThread;
        Thread m_migrationThread;

        bool sourceToTfsAnalysisComplete
        {
            get
            {
                lock (m_statelock)
                {
                    return m_sourceToTfsAnalysisComplete;
                }
            }
            set
            {
                Debug.Assert(value);

                lock (m_statelock)
                {
                    m_sourceToTfsAnalysisComplete = value;
                }
            }
        }

        bool tfsToSourceAnalysisComplete
        {
            get
            {
                lock (m_statelock)
                {
                    return m_tfsToSourceAnalysisComplete;
                }
            }
            set
            {
                Debug.Assert(value);

                lock (m_statelock)
                {
                    m_tfsToSourceAnalysisComplete = value;
                }
            }
        }

        protected override void NonFatalError(object sender, ExceptionEventArgs e)
        {
            // Exceptions are always rethrown
            if (e.Exception != null)
            {
                throw e.Exception;
            }

            // we don't want to abort on nonfatalerror. send an warning and skip the error
            OnMigrationWarning(new VersionControlEventArgs(e.Failure.Message, SystemType.Other));
        }

        protected override void DoSynchronize(SystemType primarySystem)
        {
            if (primarySystem == SystemType.Other)
            {
                // One way wss to tfs migration
                m_tfsToWssManager = null;
                m_wssToTfsManager = new SqlChangeGroupingMananger(
                new WssMigrationItemSerialzier(),
                new TfsMigrationItemSerialzier(),
                this,
                MigrationDirection.SourceToTfs);
            }
            else
            {
                // One way tfs to wss migration
                m_wssToTfsManager = null;
                m_tfsToWssManager = new SqlChangeGroupingMananger(
                    new TfsMigrationItemSerialzier(),
                    new WssMigrationItemSerialzier(),
                    this,
                    MigrationDirection.TfsToSource);
            }
            startSyncThreads();
        }

        protected override void InitializeSession()
        {
            base.InitializeSession();
            Util.CreateWssSchema();
        }
        protected override void DoSynchronizeFull()
        {
            if (m_wssToTfsManager == null)
            {
                m_wssToTfsManager = m_wssToTfsManager = new SqlChangeGroupingMananger(
                new WssMigrationItemSerialzier(),
                new TfsMigrationItemSerialzier(),
                this,
                MigrationDirection.SourceToTfs);
            }

            if (m_tfsToWssManager == null)
            {
                m_tfsToWssManager = new SqlChangeGroupingMananger(
                   new TfsMigrationItemSerialzier(),
                   new WssMigrationItemSerialzier(),
                   this,
                   MigrationDirection.TfsToSource);
            }
            startSyncThreads();
        }

        private void startSyncThreads()
        {
            m_tfsToSourceAnalysisComplete = false;
            m_sourceToTfsAnalysisComplete = false;

            m_analysisThread = new Thread(AnalysisThread);
            m_analysisThread.Start();

            m_migrationThread = new Thread(MigrationThread);
            m_migrationThread.Start();
        }


        bool m_sourceToTfsAnalysisComplete;
        bool m_tfsToSourceAnalysisComplete;

        object m_statelock = new object();
    }
}
